#if defined(TSINGMA)
#if (FEATURE_MODE == 0)
/**
 @file sys_tsingma_monitor.c

 @date 2020-8-28

 @version v1.0
*/

/***************************************************************
 *
 * Header Files
 *
 ***************************************************************/
#include "sal.h"
#include "ctc_error.h"
#include "ctc_debug.h"

#include "sys_usw_common.h"
#include "sys_usw_monitor.h"
#include "sys_usw_port_api.h"
#include "sys_usw_register.h"
#include "sys_usw_dma.h"
#include "sys_usw_efd.h"
#include "drv_api.h"

extern int32
_sys_usw_monitor_get_mburst_level(uint8 lchip, uint8 *level, uint64 thrd);

int32
sys_tsingma_monitor_sync_latency(uint8 lchip, ctc_monitor_data_t *p_data,
                                     void* p_latency_param, uint64* p_ts)
{
     uint8 info_type = 0;
     uint16 channel_id = 0;
     uint8 idx = 0;
     uint8 gchip = 0;
     uint16 lport = 0;
     uint32 gport = 0;
     uint16 msg_idx = 0;
     ctc_monitor_msg_t *p_msg = NULL;
     ms_latency_mon_tm_t *p_latency = (ms_latency_mon_tm_t *)p_latency_param;

     SYS_MONITOR_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
     msg_idx = p_data->msg_num;
     p_msg =  (ctc_monitor_msg_t*)p_data->p_msg +msg_idx;
     p_msg->monitor_type = CTC_MONITOR_LATENCY;
     p_msg->timestamp = *p_ts;
     CTC_ERROR_RETURN(sys_usw_get_gchip_id(lchip, &gchip));
     p_msg->gchip = gchip;
     channel_id = p_latency->u.event.channelId;
     /*Need mapping from channel to lport*/
     lport = SYS_MAP_SYS_LPORT_TO_DRV_LPORT(SYS_GET_LPORT_ID_WITH_CHAN(lchip, 0, channel_id));
     sys_usw_get_gchip_id(lchip, &gchip);
     gport = SYS_MAP_DRV_LPORT_TO_CTC_GPORT(gchip, lport);

     info_type = p_latency->u.event.infoType;

     if (0 == info_type)
     {
         p_msg->msg_type = CTC_MONITOR_MSG_STATS;
         p_msg->u.latency_stats.gport = gport;
         p_msg->u.latency_stats.threshold_cnt[0] = p_latency->u.mon.latencyThrdCnt0_23_0;
         p_msg->u.latency_stats.threshold_cnt[1] = p_latency->u.mon.latencyThrdCnt1_23_0;
         p_msg->u.latency_stats.threshold_cnt[2] = p_latency->u.mon.latencyThrdCnt2_23_8  << 8  | p_latency->u.mon.latencyThrdCnt2_7_0;
         p_msg->u.latency_stats.threshold_cnt[3] = p_latency->u.mon.latencyThrdCnt3_23_16 << 16 | p_latency->u.mon.latencyThrdCnt3_15_0;
         p_msg->u.latency_stats.threshold_cnt[4] = p_latency->u.mon.latencyThrdCnt4_23_0;
         p_msg->u.latency_stats.threshold_cnt[5] = p_latency->u.mon.latencyThrdCnt5_23_0;
         p_msg->u.latency_stats.threshold_cnt[6] = p_latency->u.mon.latencyThrdCnt6_23_8  << 8  | p_latency->u.mon.latencyThrdCnt6_7_0;
         p_msg->u.latency_stats.threshold_cnt[7] = p_latency->u.mon.latencyThrdCnt7_23_16 << 16 | p_latency->u.mon.latencyThrdCnt7_15_0;

         for (idx = 0; idx < 8; idx++)
         {
             p_usw_monitor_master[lchip]->latency_stats[channel_id][idx] += p_msg->u.latency_stats.threshold_cnt[idx];
         }
     }
     else
     {
         p_msg->msg_type = CTC_MONITOR_MSG_EVENT;
         p_msg->u.latency_event.gport = gport;

         p_msg->u.latency_event.event_state = p_latency->u.event.valid;
         p_msg->u.latency_event.source_port = SYS_MAP_DRV_GPORT_TO_CTC_GPORT(p_latency->u.event.sourcePort);
         p_msg->u.latency_event.port = p_latency->u.event.localPhyPort;
         p_msg->u.latency_event.level = p_latency->u.event.region;
         p_msg->u.latency_event.event_state = (p_msg->u.latency_event.event_state == 1) ? CTC_MONITOR_EVENT_STATE_OCCUR:CTC_MONITOR_EVENT_STATE_CLEAR;
         p_msg->u.latency_event.latency = ((uint64)p_latency->u.event.residenceTime_47_44 << 44) | ((uint64)p_latency->u.event.residenceTime_43_12 << 12) | p_latency->u.event.residenceTime_11_0;
         p_msg->timestamp = ((uint64)p_latency->u.event.timestamp_63_44 << 44) | ((uint64)p_latency->u.event.timestamp_43_12 << 12) | p_latency->u.event.timestamp_11_0;
     }

     msg_idx++;
     p_data->msg_num = msg_idx;
    return CTC_E_NONE;
}

int32
sys_tsingma_monitor_sync_buffer(uint8 lchip, ctc_monitor_data_t *p_data,
                                   void* p_buffer_param, uint64* p_ts, uint8 msg_type, uint8 dir, uint8 dp)
{
    uint8 info_type = 0;
    uint16 channel_id = 0;
    uint8 gchip = 0;
    uint16 lport = 0;
    uint32 gport = 0;
    uint16 msg_idx = 0;
    ctc_monitor_msg_t *p_msg = NULL;
    uint32 sc_cnt[SYS_MONITOR_SC_NUM_MAX] = {0};
    uint32 cmd = 0;
    uint32 field_val = 0;
    uint32 buffer_cnt = 0;
    uint8 queue_type = 0;
    uint8 burst_type = 0;
    uint8 level = 0;
    uint8 idx = 0;
    uint64 timestamp = 0;

    msg_idx = p_data->msg_num;
    p_msg = (ctc_monitor_msg_t*)p_data->p_msg +msg_idx;
    p_msg->monitor_type = CTC_MONITOR_BUFFER;
    CTC_ERROR_RETURN(sys_usw_get_gchip_id(lchip, &gchip));
    p_msg->gchip = gchip;

    if(dir == CTC_EGRESS)
    {
        if(msg_type == CTC_MONITOR_MSG_STATS)
        {
            temp_erm_resrc_mon_info_tm_t *p_buffer = (temp_erm_resrc_mon_info_tm_t *)p_buffer_param;
            p_msg->u.buffer_stats.dir = CTC_EGRESS;
            info_type = p_buffer->u.g1.monInfoType;

            if (0 == info_type)
            {
                p_msg->msg_type = CTC_MONITOR_MSG_STATS;
                p_msg->timestamp = *p_ts;
                channel_id = p_buffer->u.g1.channelId;

                /*Need mapping from channel to lport*/
                lport = SYS_MAP_SYS_LPORT_TO_DRV_LPORT(SYS_GET_LPORT_ID_WITH_CHAN(lchip, 0, channel_id));
                sys_usw_get_gchip_id(lchip, &gchip);
                gport = SYS_MAP_DRV_LPORT_TO_CTC_GPORT(gchip, lport);

                p_msg->u.buffer_stats.gport = gport;
                p_msg->u.buffer_stats.buffer_type = CTC_MONITOR_BUFFER_PORT;
                p_msg->u.buffer_stats.buffer_cnt  = p_buffer->u.g1.pktBufCnt;

                p_usw_monitor_master[lchip]->buffer_stats[channel_id][0] = p_buffer->u.g1.ucastBufCnt;
                p_usw_monitor_master[lchip]->buffer_stats[channel_id][1] = p_buffer->u.g1.mcastBufCnt;

                msg_idx++;
            }
            else if(1 == info_type)
            {
                sc_cnt[0] = p_buffer->u.g2.scCnt_0;
                sc_cnt[1] = p_buffer->u.g2.scCnt_1;
                sc_cnt[2] = p_buffer->u.g2.scCnt_2;
                sc_cnt[3] = p_buffer->u.g2.scCnt_3;
                for (idx = 0; idx < SYS_MONITOR_SC_NUM_MAX; idx++)
                {
                    p_msg = (ctc_monitor_msg_t*)p_data->p_msg + msg_idx;
                    p_msg->gchip = gchip;
                    p_msg->monitor_type = CTC_MONITOR_BUFFER;
                    p_msg->msg_type = CTC_MONITOR_MSG_STATS;
                    p_msg->u.buffer_stats.sc  = idx;
                    p_msg->u.buffer_stats.dir = CTC_EGRESS;
                    p_msg->u.buffer_stats.buffer_cnt  = sc_cnt[idx];
                    p_msg->u.buffer_stats.buffer_type = CTC_MONITOR_BUFFER_SC;
                    msg_idx++;
                }
            }
            else if(2 == info_type)
            {
                p_msg->msg_type = CTC_MONITOR_MSG_STATS;
                p_msg->u.buffer_stats.buffer_cnt = p_buffer->u.g3.totalCnt;
                p_msg->u.buffer_stats.buffer_type = CTC_MONITOR_BUFFER_TOTAL;
                p_usw_monitor_master[lchip]->total_stats = p_msg->u.buffer_stats.buffer_cnt;
                msg_idx++;
            }
            else if(3 == info_type)
            {
                p_msg->msg_type = CTC_MONITOR_MSG_STATS;
                cmd = DRV_IOR(ErmResrcMonPortCtl_t, ErmResrcMonPortCtl_resrcMonPortId_f);
                CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &field_val));
                lport = SYS_MAP_SYS_LPORT_TO_DRV_LPORT(SYS_GET_LPORT_ID_WITH_CHAN(lchip, 0, field_val));
                sys_usw_get_gchip_id(lchip, &gchip);
                gport = SYS_MAP_DRV_LPORT_TO_CTC_GPORT(gchip, lport);
                p_msg->u.buffer_stats.queue_id.gport = gport;
                queue_type = p_buffer->u.g4.detailedType;
                if (0 == queue_type || 1 == queue_type)
                {
                    p_msg->u.buffer_stats.queue_id.queue_type = CTC_QUEUE_TYPE_NETWORK_EGRESS;
                }
                p_msg->u.buffer_stats.queue_id.queue_id = p_buffer->u.g4.queueOffset;
                p_msg->u.buffer_stats.buffer_cnt = p_buffer->u.g4.queueCnt;
                p_msg->u.buffer_stats.buffer_type = CTC_MONITOR_BUFFER_QUEUE;
                msg_idx++;
            }
        }
        else if(msg_type == CTC_MONITOR_MSG_EVENT)
        {
            temp_erm_mb_mon_info_tm_t *p_buffer = (temp_erm_mb_mon_info_tm_t *)p_buffer_param;
            p_msg->msg_type = CTC_MONITOR_MSG_EVENT;
            p_msg->timestamp = *p_ts;
            burst_type = p_buffer->microburstType;
            switch(burst_type)
            {
            case 1:
                channel_id = (p_buffer->u_data >> 2) & 0x3F;
                /*Need mapping from channel to lport*/
                lport = SYS_GET_LPORT_ID_WITH_CHAN(lchip, 0, channel_id);
                lport = SYS_MAP_SYS_LPORT_TO_DRV_LPORT(lport);
                sys_usw_get_gchip_id(lchip, &gchip);
                gport = SYS_MAP_DRV_LPORT_TO_CTC_GPORT(gchip, lport);

                p_msg->u.buffer_event.gport = gport;
                p_msg->u.buffer_event.buffer_type = CTC_MONITOR_BUFFER_PORT;
                p_msg->u.buffer_event.uc_cnt            =  p_buffer->u.channel.ucastBufCnt;
                p_msg->u.buffer_event.mc_cnt            =  p_buffer->u.channel.mcastBufCnt;
                p_msg->u.buffer_event.threshold_level   =  p_buffer->u_data & 0x3;

                field_val = p_usw_monitor_master[lchip]->mb_thrd->port_thrd[channel_id][1];
                buffer_cnt = p_msg->u.buffer_event.uc_cnt + p_msg->u.buffer_event.mc_cnt;
                break;
             case 2:
                p_msg->u.buffer_event.buffer_type = CTC_MONITOR_BUFFER_TOTAL;
                p_msg->u.buffer_event.buffer_cnt =  p_buffer->u.total.totalCnt;
                field_val = p_usw_monitor_master[lchip]->mb_thrd->total_thrd[1];
                buffer_cnt = p_msg->u.buffer_event.buffer_cnt;
                break;
             case 3:
                p_msg->u.buffer_event.buffer_type = CTC_MONITOR_BUFFER_SC;
                p_msg->u.buffer_event.buffer_cnt =  p_buffer->u.sc.scCnt;
                p_msg->u.buffer_event.sc =  p_buffer->u.sc.id;
                field_val = p_usw_monitor_master[lchip]->mb_thrd->sc_thrd[p_buffer->u.sc.id][1];
                CTC_ERROR_RETURN(DRV_FIELD_IOCTL(lchip, 0, cmd, &field_val));
                buffer_cnt = p_msg->u.buffer_event.buffer_cnt;
                break;
             case 4:
                p_msg->u.buffer_event.buffer_type = CTC_MONITOR_BUFFER_CONTROL;
                p_msg->u.buffer_event.buffer_cnt =  p_buffer->u.critical.criticalCnt;
                field_val = p_usw_monitor_master[lchip]->mb_thrd->critical_thrd[1];
                buffer_cnt = p_msg->u.buffer_event.buffer_cnt;
                break;
             case 5:
                p_msg->u.buffer_event.buffer_type = CTC_MONITOR_BUFFER_C2C;
                p_msg->u.buffer_event.buffer_cnt =  p_buffer->u.c2c.c2cCnt;
                field_val = p_usw_monitor_master[lchip]->mb_thrd->c2c_thrd[1];
                buffer_cnt = p_msg->u.buffer_event.buffer_cnt;
                break;
            }

            p_msg->u.buffer_event.event_state = (buffer_cnt >= field_val) ? CTC_MONITOR_EVENT_STATE_OCCUR:CTC_MONITOR_EVENT_STATE_CLEAR;
            msg_idx++;
            
            if(p_msg->u.buffer_event.event_state == CTC_MONITOR_EVENT_STATE_OCCUR && p_msg->u.buffer_event.buffer_type == CTC_MONITOR_BUFFER_PORT)
            {
                p_usw_monitor_master[lchip]->mburst_timestamp[channel_id] = p_msg->timestamp;
            }
            else if(p_msg->u.buffer_event.event_state == CTC_MONITOR_EVENT_STATE_CLEAR && p_msg->u.buffer_event.buffer_type == CTC_MONITOR_BUFFER_PORT)
            {
                timestamp = p_msg->timestamp - p_usw_monitor_master[lchip]->mburst_timestamp[channel_id];
                _sys_usw_monitor_get_mburst_level(lchip, &level, timestamp);
                if(level != 0xff)
                {
                    p_msg = (ctc_monitor_msg_t*)p_data->p_msg +msg_idx;
                    p_msg->monitor_type = CTC_MONITOR_BUFFER;
                    p_msg->msg_type = CTC_MONITOR_MSG_MBURST_STATS;
                    p_msg->gchip = gchip;
                    p_msg->timestamp = *p_ts;
                    p_usw_monitor_master[lchip]->mburst_stats[channel_id][level] ++;
                    p_msg->u.mburst_stats.gport = gport;
                    for (idx = 0; idx < 8; idx++)
                    {
                         p_msg->u.mburst_stats.threshold_cnt[idx] = p_usw_monitor_master[lchip]->mburst_stats[channel_id][idx];
                    }
                    msg_idx++;
                }
            }
        }
        p_data->msg_num = msg_idx;
    }
    else if(dir == CTC_INGRESS)
    {
        if(msg_type == CTC_MONITOR_MSG_STATS)
        {
            temp_irm_resrc_mon_info_tm_t *p_buffer = (temp_irm_resrc_mon_info_tm_t *)p_buffer_param;
            p_msg->u.buffer_stats.dir = CTC_INGRESS;
            info_type = p_buffer->u.g1.monInfoType;

            if (0 == info_type)
            {
                p_msg->msg_type = CTC_MONITOR_MSG_STATS;
                p_msg->timestamp = *p_ts;
                channel_id = p_buffer->u.g1.channelId;

                /*Need mapping from channel to lport*/
                channel_id = dp ? channel_id + MCHIP_CAP(SYS_CAP_PER_DP_CHANNEL_NUM) : channel_id;
                lport = SYS_MAP_SYS_LPORT_TO_DRV_LPORT(SYS_GET_LPORT_ID_WITH_CHAN(lchip, 0, channel_id));
                sys_usw_get_gchip_id(lchip, &gchip);
                gport = SYS_MAP_DRV_LPORT_TO_CTC_GPORT(gchip, lport);

                p_msg->u.buffer_stats.gport = gport;
                p_msg->u.buffer_stats.buffer_type = CTC_MONITOR_BUFFER_PORT;
                p_msg->u.buffer_stats.buffer_cnt  = p_buffer->u.g1.pktBufCnt;
                msg_idx++;
            }
            else if(1 == info_type)
            {
                sc_cnt[0] = p_buffer->u.g2.scCnt_0;
                sc_cnt[1] = p_buffer->u.g2.scCnt_1;
                sc_cnt[2] = p_buffer->u.g2.scCnt_2;
                sc_cnt[3] = p_buffer->u.g2.scCnt_3;
                for (idx = 0; idx < SYS_MONITOR_SC_NUM_MAX; idx++)
                {
                    p_msg = (ctc_monitor_msg_t*)p_data->p_msg + msg_idx;
                    p_msg->gchip = gchip;
                    p_msg->monitor_type = CTC_MONITOR_BUFFER;
                    p_msg->msg_type = CTC_MONITOR_MSG_STATS;
                    p_msg->u.buffer_stats.sc  = idx;
                    p_msg->u.buffer_stats.dir = CTC_INGRESS;
                    p_msg->u.buffer_stats.buffer_cnt  = sc_cnt[idx];
                    p_msg->u.buffer_stats.buffer_type = CTC_MONITOR_BUFFER_SC;
                    msg_idx++;
                }
            }
            else if(2 == info_type)
            {
                p_msg->msg_type = CTC_MONITOR_MSG_STATS;
                p_msg->u.buffer_stats.buffer_cnt = p_buffer->u.g3.totalCnt;
                p_msg->u.buffer_stats.buffer_type = CTC_MONITOR_BUFFER_TOTAL;
                msg_idx++;
            }
        }
        p_data->msg_num = msg_idx;
    }
    return CTC_E_NONE;
}

int32
sys_tsingma_monitor_sync_data(uint8 lchip, void* p_data)
{
    uint16 entry_num = 0;
    uint16 index = 0;
    ms_dlb_efd_mon_tm_t* p_monitor = NULL;
    ms_erm_mon_tm_t* p_erm_mon = NULL;
    ms_irm_mon_tm_t* p_irm_mon = NULL;
    sys_dma_info_t* p_dma_info = (sys_dma_info_t*)p_data;
    ctc_monitor_data_t  monitor_data;
    ctc_efd_data_t efd_data;
    ds_t ds;
    uint32 type = 0;
    uint64 ts;

    sal_memset(&monitor_data, 0, sizeof(monitor_data));
    sal_memset(&efd_data, 0, sizeof(efd_data));

    if (NULL == p_usw_monitor_master[lchip])
    {
        return CTC_E_NOT_INIT;
    }

    monitor_data.p_msg = p_usw_monitor_master[lchip]->p_buffer;
    entry_num = p_dma_info->entry_num;

    for (index = 0; index < entry_num; index++)
    {
        p_monitor = ((ms_dlb_efd_mon_tm_t*)p_dma_info->p_data+index);

        type = p_monitor->monType;
        ts = (uint64)p_monitor->timestamp_53_22 << 22 | p_monitor->timestamp_21_0;

        if (type == 0) /* efd flow aging */
        {
            efd_data.flow_id_array[efd_data.count] = p_monitor->efdMonPtr;
            efd_data.count ++;

            if(efd_data.count == CTC_EFD_FLOW_ID_ARRAY_MAX)
            {
                /* process efd callback */
                sys_usw_efd_sync_data(lchip, &efd_data);
                efd_data.count = 0;
            }
        }
        else if (type == 2)
        {
            sys_tsingma_monitor_sync_latency(lchip, &monitor_data, (void*)p_monitor, &ts);
        }
        else if (type == 1)
        {
            
            p_erm_mon = (ms_erm_mon_tm_t*)p_monitor;
            /*buffer stats*/
            if(!p_erm_mon->infoType)
            {
                sal_memset(&ds, 0, sizeof(ds));
                ds[0] = (p_erm_mon->u_62_31 & 0x1) << 31 | p_erm_mon->u_30_0;
                ds[1] = (p_erm_mon->u_62_31 >> 1) & 0x3FFFFFFF;
                sys_tsingma_monitor_sync_buffer(lchip, &monitor_data, (void*)&ds, &ts, CTC_MONITOR_MSG_STATS, CTC_EGRESS, 0);
            }
            else/*buffer event*/
            {
                sal_memset(&ds, 0, sizeof(ds));
                if((p_erm_mon->u_62_31 >> 12) & 0x1)
                {
                    ds[0] = (p_erm_mon->u_62_31 & 0x1) << 31 | p_erm_mon->u_30_0;
                    ds[1] = (p_erm_mon->u_62_31 >> 1) & 0x3FF;
                    sys_tsingma_monitor_sync_buffer(lchip, &monitor_data, (void*)&ds, &ts, CTC_MONITOR_MSG_EVENT, CTC_EGRESS, 0);
                }

                if((p_erm_mon->u_94_63 >> 24) & 0x1)
                {
                    ds[0] = (p_erm_mon->u_94_63 & 0x1FFF) << 19 | p_erm_mon->u_62_31 >> 13;
                    ds[1] = (p_erm_mon->u_94_63 >> 13) & 0x3FF;
                    sys_tsingma_monitor_sync_buffer(lchip, &monitor_data, (void*)&ds, &ts, CTC_MONITOR_MSG_EVENT, CTC_EGRESS, 0);
                }

            }
        }
        else if (type == 3)
        {
            p_irm_mon = (ms_irm_mon_tm_t*)p_monitor;
            /*buffer stats*/
            if(!p_irm_mon->infoType)
            {
                sal_memset(&ds, 0, sizeof(ds));
                ds[0] = (p_irm_mon->u_62_31 & 0x1) << 31 | p_irm_mon->u_30_0;
                ds[1] = (p_irm_mon->u_62_31 >> 1) & 0x3FFFFFFF;
                sys_tsingma_monitor_sync_buffer(lchip, &monitor_data, (void*)&ds, &ts, CTC_MONITOR_MSG_STATS,CTC_INGRESS,0);
            }
        }

        /*CallBack*/
        if (p_usw_monitor_master[lchip]->func && monitor_data.msg_num >= MCHIP_CAP(SYS_CAP_MONITOR_SYNC_CNT)*4)
        {
            p_usw_monitor_master[lchip]->func(&monitor_data, p_usw_monitor_master[lchip]->user_data);
            monitor_data.p_msg = p_usw_monitor_master[lchip]->p_buffer;
            monitor_data.msg_num = 0;
        }
    }




    /*CallBack*/
    if (p_usw_monitor_master[lchip]->func && monitor_data.msg_num != 0)
    {
        p_usw_monitor_master[lchip]->func(&monitor_data, p_usw_monitor_master[lchip]->user_data);
    }
    if(efd_data.count != 0)
    {
        /* process efd callback */
        sys_usw_efd_sync_data(lchip, &efd_data);
    }

    return CTC_E_NONE;
}

#endif

#endif

